<!--
 * Copyright 2010, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>WebGL High Dynamic Range Demo</title>
<style>
body {
  width: 100%;
  height: 100%;
  border: 0px;
  padding: 0px;
  margin: 0px;
  background-color: white;
}
canvas {
  background-color: red;
}
canvas.invisible {
  display: none;
}
#controls {
  z-index: 2;
  position: absolute;
  left: 10px;
  bottom: 10px;
  background-color: #FFEE99;
  display: table;
}
#beat {
  display: table-cell;
  font-family: sans-serif;
  margin: 4px;
  padding: 4px;
  border-width: 1px;
  vertical-align: middle;
}
#viewContainer {
  width: 100%;
  height: 100%;
}
.fpsContainer {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  color: gray;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
div.title {
  font-weight: bold;
}
</style>
<script src="../jquery-ui-1.8.2.custom/js/jquery-1.4.2.min.js"></script>
<script src="../tdl/base.js"></script>
<script src="jshashtable-2.1.js"></script>
<script src="SphericalCameraController.js"></script>
<script src="hdr.js"></script>

<!----- Skybox shaders ----->

<script id="skyboxVertexShader" type="text/something-not-javascript">
attribute vec4 position;
varying vec4 v_position;
void main() {
  v_position = position;
  gl_Position = position;
}
</script>

<script id="skyboxFragmentShader" type="text/something-not-javascript">
#ifdef GL_FRAGMENT_PRECISION_HIGH
  precision highp float;
#else
  precision mediump float;
#endif


uniform samplerCube u_skybox;
uniform mat4 u_viewDirectionProjectionInverse;
varying vec4 v_position;
void main() {
  vec4 t = u_viewDirectionProjectionInverse * v_position;
  gl_FragColor = textureCube(
      u_skybox,
      normalize(t.xyz / t.w));
}
</script>

<!----- Diffuse shader (testing purposes only, currently unused) ----->

<script id="diffuseVertexShader" type="text/something-not-javascript">
attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;

uniform mat4 u_worldViewProjection;
uniform mat4 u_worldView;
uniform mat4 u_world;

varying vec4 v_color;
varying vec3 v_normal;
varying vec3 v_eyeDir;

void main(void) {
  v_color = color;
  v_normal = (u_world * vec4(normalize(normal), 0.0)).xyz;
  v_eyeDir = -normalize((u_worldView * vec4(position, 1.0)).xyz);
  gl_Position = u_worldViewProjection * vec4(position, 1.0);
}
</script>
<script id="diffuseFragmentShader" type="text/something-not-javascript">
precision mediump float;

varying vec4 v_color;
varying vec3 v_normal;
uniform vec3 u_lightDir;
uniform vec4 u_lightColor;
varying vec3 v_eyeDir;
void main(void) {
  float light = max(0.0, dot(normalize(u_lightDir), v_normal));
  float glare = max(0.0, dot(v_normal, normalize(v_eyeDir + u_lightDir)));
  glare = glare*glare;
  glare = glare*glare;
  glare = glare*glare;
  glare = glare*glare;
  glare = glare*glare;
  glare = glare*glare;
  vec4 ambient = v_color;
  // Gamma correction approximation (sqrt)
  vec4 finalColor = sqrt(ambient + light * u_lightColor + glare);
  finalColor.w = 1.0;
  gl_FragColor = finalColor;
}
</script>

<!----- Irradiance shader ----->

<script id="irradianceVertexShader" type="text/something-not-javascript">
attribute vec3 position;
attribute vec3 normal;

uniform mat4 u_world;
uniform mat4 u_worldViewProjection;

varying vec3 v_normal;

void main(void) {
  v_normal = (u_world * vec4(normalize(normal), 0.0)).xyz;
  gl_Position = u_worldViewProjection * vec4(position, 1.0);
}
</script>

<script id="irradianceFragmentShader" type="text/something-not-javascript">
precision mediump float;

varying vec3 v_normal;
uniform samplerCube u_irradianceMap;
void main(void) {
  vec3 normal = normalize(v_normal);
  vec4 color = textureCube(u_irradianceMap, normal);
  gl_FragColor = color;
}
</script>

<!----- Reflection shader ----->

<script id="reflectionVertexShader" type="text/something-not-javascript">
attribute vec3 position;
attribute vec3 normal;

uniform mat4 u_world;
uniform mat4 u_view;
uniform mat4 u_worldViewProjection;

varying vec3 v_normal;
varying vec3 v_worldEyeVec;

void main(void) {
  v_normal = (u_world * vec4(normalize(normal), 0.0)).xyz;
  vec4 worldPosition = u_worldViewProjection * vec4(position, 1.0);
  vec3 worldEyePos = u_view[3].xyz;
  gl_Position = worldPosition;
  v_worldEyeVec = normalize(worldPosition.xyz - worldEyePos);
}
</script>

<script id="reflectionFragmentShader" type="text/something-not-javascript">
precision mediump float;

varying vec3 v_normal;
varying vec3 v_worldEyeVec;
uniform vec3 u_diffuseColor;
uniform float u_shininess;
uniform samplerCube u_irradianceMap;
uniform samplerCube u_reflectionMap;
void main(void) {
  vec3 normal = normalize(v_normal);
  vec4 irradiance = textureCube(u_irradianceMap, normal);
  vec4 reflection = textureCube(u_reflectionMap, reflect(v_worldEyeVec, normal));
  gl_FragColor = vec4(u_diffuseColor, 1.0) + (1.0 - u_shininess) * irradiance + u_shininess * reflection;
}
</script>

<!----- HDRPipeline vertex shader ----->

<script id="hdrPipelineVertexShader" type="text/something-not-javascript">
attribute vec4 position;
varying vec2 v_texCoord;
void main() {
  v_texCoord = (position.xy + 1.0) * 0.5;
  gl_Position = position;
}
</script>

<!----- Various pipeline stages' fragment shaders ---->

<script id="discardLDRShader" type="text/something-not-javascript">
precision mediump float;

varying vec2 v_texCoord;
uniform sampler2D u_source;

void main() {
  vec4 c = texture2D(u_source, v_texCoord);
  gl_FragColor = step(THRESHOLD, c);
}
</script>

<script id="bicubicUpsamplingVertexShader" type="text/something-not-javascript">
attribute vec4 position;
varying vec2 v_texCoord;
uniform mediump vec2 u_imageIncrement;
void main() {
  v_texCoord = (position.xy + 1.0) * 0.5 - vec2(0.5, 0.5) * u_imageIncrement;
  gl_Position = position;
}
</script>

<script id="bicubicUpsamplingShader" type="text/something-not-javascript">
precision mediump float;

varying vec2 v_texCoord;
uniform sampler2D u_source;
uniform vec2 u_imageIncrement;
uniform mat4 u_coefficients;

// TODO(kbr): incorporate half-pixel offset of incoming texture
// coordinates in vertex shader for correctness.

vec4 cubicBlend(float t, vec4 c0, vec4 c1, vec4 c2, vec4 c3) {
  vec4 ts = vec4(1.0, t, t * t, t * t * t);
  vec4 result = u_coefficients * ts;
  return result.w * c0 + result.z * c1 + result.y * c2 + result.x * c3;
}

void main() {
   vec2 f = fract(v_texCoord / u_imageIncrement);
  vec4 t00 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2(-1.0, -1.0));
  vec4 t10 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 0.0, -1.0));
  vec4 t20 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 1.0, -1.0));
  vec4 t30 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 2.0, -1.0));
  vec4 t0 = cubicBlend(f.x, t00, t10, t20, t30);
  vec4 t01 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2(-1.0, 0.0));
  vec4 t11 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 0.0, 0.0));
  vec4 t21 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 1.0, 0.0));
  vec4 t31 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 2.0, 0.0));
  vec4 t1 = cubicBlend(f.x, t01, t11, t21, t31);
  vec4 t02 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2(-1.0, 1.0));
  vec4 t12 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 0.0, 1.0));
  vec4 t22 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 1.0, 1.0));
  vec4 t32 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 2.0, 1.0));
  vec4 t2 = cubicBlend(f.x, t02, t12, t22, t32);
  vec4 t03 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2(-1.0, 2.0));
  vec4 t13 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 0.0, 2.0));
  vec4 t23 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 1.0, 2.0));
  vec4 t33 = texture2D(u_source, v_texCoord + u_imageIncrement * vec2( 2.0, 2.0));
  vec4 t3 = cubicBlend(f.x, t03, t13, t23, t33);
  gl_FragColor = cubicBlend(f.y, t0, t1, t2, t3);
}
</script>

<script id="toneMappingShader" type="text/something-not-javascript">
precision mediump float;

varying vec2 v_texCoord;
uniform sampler2D u_source;
uniform sampler2D u_blurred;
uniform float u_blurAmount;
uniform sampler2D u_gammaTexture;
uniform float u_exposure;

void main() {
  vec4 c0 = texture2D(u_source, v_texCoord);
  vec4 c1 = texture2D(u_blurred, v_texCoord);
  vec4 c = mix(c0, c1, u_blurAmount) * u_exposure;

#if 1
  float r = texture2D(u_gammaTexture, vec2(c.r, 0.5)).r;
  float g = texture2D(u_gammaTexture, vec2(c.g, 0.5)).r;
  float b = texture2D(u_gammaTexture, vec2(c.b, 0.5)).r;
#else
  float r = pow(c.r, 1.0 / 2.2);
  float g = pow(c.g, 1.0 / 2.2);
  float b = pow(c.b, 1.0 / 2.2);
#endif
  gl_FragColor = vec4(r, g, b, 1.0);
}
</script>

</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
</body>
</html>
